package com.guanyou.lock;

import com.guanyou.RedisUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCommands;

import java.util.Collections;


public class RedisLock extends IDLock {
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "EX";
    private static final Long RELEASE_SUCCESS = 1L;
    static final String THREAD_ID = "RedisLock:ThreadID";
    static final int EXPIRE = 30;
    RedisUtil redis;
    String lockName;

    public RedisLock(RedisUtil redis, String lockName) {
        this.redis = redis;
        this.lockName = lockName;
    }

    @Override
    protected long getThreadId() {
        JedisCommands cmd = redis.getJedis();
        //String keyName = lockName+":"+THREAD_ID;
        //Long id = cmd.incrBy(keyName, 1);
        Long id = cmd.hincrBy(lockName, THREAD_ID, 1);
        redis.returnJedis(cmd);
        return id;
    }

    @Override
    protected void lock(Long res, Long threadId) {
        String key = lockName + res;
        String v = "" + threadId;
        JedisCommands cmd = redis.getJedis();
        String value = cmd.get(key);
        if (value != null && v.equals(value)) return;
        while (true) {
            String result = cmd.set(key, v, SET_IF_NOT_EXIST);
            if (LOCK_SUCCESS.equals(result)) {

                break;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                //return; // wait up when killed?
            }
        }
        redis.returnJedis(cmd);
    }

    @Override
    protected void unlock(Long res, Long threadId) {
        Jedis cmd = redis.getRriginalJedis();
        String key = lockName + res;
        String v = "" + threadId;
        assert v.equals(cmd.get(key));
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        cmd.eval(script, Collections.singletonList(key), Collections.singletonList(v));
        redis.returnJedis(cmd);
    }
}
